﻿namespace WLFramework.Mapping
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using WLFramework.Common;
    
    /// <summary>
    /// 类型映射， 对不在继承体系树内的2个类进行值拷贝， 将原始“类"的属性、字段拷贝到目标类型的对应属性、字段上。
    /// </summary>
    public class ObjectMapper
    {
        private static SafeDictionary<int, SafeDictionary<int, MapperInfo>> mapperInfoCaches =
            new SafeDictionary<int, SafeDictionary<int, MapperInfo>>();

        private static SafeDictionary<int, SafeDictionary<int, ObjectMapper>> mapperCaches = 
            new SafeDictionary<int, SafeDictionary<int, ObjectMapper>>();

        /// <summary>
        /// 原始类型与目标类型关系的元数据
        /// </summary>
        public MapperInfo MapperInfo { get; private set; }

        /// <summary>
        /// 构建一个完成类型之间值的拷贝的对象
        /// </summary>
        /// <param name="from">原始类型</param>
        /// <param name="to">目标类型</param>
        public ObjectMapper(Type from, Type to)
        {
            int fromHashCode = from.GetHashCode();
            int toHashCode = to.GetHashCode();

            SafeDictionary<int, MapperInfo> mapper;
            MapperInfo info;
            if (mapperInfoCaches.TryGetValue(fromHashCode, out mapper))
            {
                if (mapper.TryGetValue(toHashCode, out info))
                {
                    this.MapperInfo = info;
                    return;
                }
            }

            if (mapper == null)
            {
                mapperInfoCaches[fromHashCode] = mapper = new SafeDictionary<int, MapperInfo>();
            }

            this.MapperInfo = mapper[toHashCode] = new MapperInfo(from, to);
        }

        /// <summary>
        /// 使用现有的类型关系元数据构建一个对象
        /// </summary>
        /// <param name="info">原始类型与目标类型关系的元数据</param>
        public ObjectMapper(MapperInfo info)
        {
            this.MapperInfo = info;
        }

        /// <summary>
        /// 将原始对象拷贝到目标对象
        /// </summary>
        /// <param name="from">原始对象</param>
        /// <param name="to">目标对象</param>
        public void Mapping(object from, object to)
        {
            // query from -> to
            //   init Mapper
            //   ->get __from
            //   ->init __to
            //   ->call Mapper.Mapping __from __to
            //   get from
            //   set to

            Shield.AssertIsTrue(!this.MapperInfo.IsPrimitive);

            foreach (var info in this.MapperInfo.MapperInfos)
            {
                if (!info.IsPrimitive && (info.From != info.To))
                {                    
                    object fromValue = info.Getter.Getter(from);
                    if (fromValue != null)
                    {
                        ObjectMapper mapper = new ObjectMapper(info);                        
                        object toValue = info.Creater.Ctor();
                        info.Setter.Setter(to, toValue);
                        mapper.Mapping(fromValue, toValue);
                    }
                }
                else
                {
                    object fromValue = info.Getter.Getter(from);
                    info.Setter.Setter(to, fromValue);
                }
            }
        }
        
        /// <summary>
        /// 构建一个完成类型之间值的拷贝的对象
        /// </summary>
        /// <typeparam name="TFrom">原始类型</typeparam>
        /// <typeparam name="TTo">目标类型</typeparam>
        /// <returns>ObjectMapper对象</returns>
        public static ObjectMapper CreateMapper<TFrom, TTo>()
        {
            Type from = typeof(TFrom);
            Type to = typeof(TTo);
            int fromHashCode = from.GetHashCode();
            int toHashCode = to.GetHashCode();

            SafeDictionary<int, ObjectMapper> mappers;
            ObjectMapper mapper;
            if (mapperCaches.TryGetValue(fromHashCode, out mappers))
            {
                if (mappers.TryGetValue(toHashCode, out mapper))
                {
                    return mapper;
                }
            }

            if (mappers == null)
            {
                mapperCaches[fromHashCode] = mappers = new SafeDictionary<int, ObjectMapper>();
            }

            mappers[toHashCode] = mapper = new ObjectMapper(typeof(TFrom), typeof(TTo));
            return mapper;
        }

        /// <summary>
        /// 将原始对象拷贝到目标对象
        /// </summary>
        /// <typeparam name="TFrom">原始对象</typeparam>
        /// <typeparam name="TTo">目标对象</typeparam>
        /// <param name="from">原始类型</param>
        /// <param name="to">目标类型</param>
        public static void ObjectMapping<TFrom, TTo>(TFrom from, TTo to)
        {
            CreateMapper<TFrom, TTo>().Mapping(from, to);
        }
    }
}
